﻿using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;

namespace devtm.Aop.Convert
{
    
    public class ImplementContainer
    {


        ModuleDefinition targetmodule;


        public ImplementContainer(ModuleDefinition targetModule)
        {
            Methods = new Dictionary<string, BoxMethodDefinition>();
            Fields = new Dictionary<string, BoxFieldReference>();

            this.targetmodule = targetModule;

        }


        internal Dictionary<string, BoxMethodDefinition> Methods { get; set; }
        internal Dictionary<string, BoxFieldReference> Fields { get; set; }

        public bool MustBeImplment
        {
            get
            {
                return Methods.Count > 0 || Fields.Count > 0;
            }
        }

        public void Add(MethodInfo method, MethodInfo methodInterface)
        {

            MethodDefinition m = targetmodule.Import(method).Resolve();
            MethodDefinition m2 = targetmodule.Import(methodInterface).Resolve();
            
            Add(m, m2);

        }

        private void Add(MethodDefinition m, MethodDefinition methodInterface)
        {

            string name = m.ToString();
            
            if (!Methods.ContainsKey(name))
            {

                Methods.Add(name, new BoxMethodDefinition(m) { MethodInterface = methodInterface });

                foreach (var item in m.Body.Instructions)
                    if (item.Operand != null & !(item.Operand is TypeReference) && item.Operand is MemberReference)
                    {

                        var m1 = item.Operand as MemberReference;

                        if (m1.DeclaringType.ToString() == m.DeclaringType.ToString())
                        {

                            if (item.Operand is FieldReference)
                            {

                                var f = item.Operand as FieldReference;
                                name = f.ToString();

                                if (!Fields.ContainsKey(name))                                
                                    Fields.Add(name, new BoxFieldReference(f.Resolve()));
                                
                            }
                            else if (item.Operand is MethodDefinition)
                                Add(item.Operand as MethodDefinition, null);
                            
                            else if (item.Operand is MethodReference)
                                Add((item.Operand as MethodReference).Resolve(), null);
                            
                            else
                            {

                            }
                        }
                    }                

            }
            else
            {
                var me = Methods[name];
                if (me.MethodInterface == null && methodInterface != null)
                    me.MethodInterface = methodInterface;
            }
        }


    }

}
